/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * MergePanel.java
 *
 * Created on Mar 2, 2011, 3:38:01 PM
 */
package thesis.view;

import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import util.Config;
import util.ID;
import util.JSREDocument;
import util.JSRELine;
import util.ReadWriteFile;
import util.TextFilter;
import org.jdesktop.application.Action;
import util.Document;

/**
 *
 * @author banhbaochay
 */
public class MergePanel extends javax.swing.JPanel {

    public static final int JSRE_MODE = 0;
    public static final int NORMAL_MODE = 1;

    /** Creates new form MergePanel
     * @param mapConfig 
     */
    public MergePanel(HashMap<String, String> mapConfig) {
        this.mapConfig = mapConfig;
        initData();
        initComponents();
    }

    private void initData() {
        Object[] colMerge = {"File", "Line number in Text - Length"};
        mergeModel = new DefaultTableModel(colMerge, 0);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        popupMenu = new javax.swing.JPopupMenu();
        editItem = new javax.swing.JMenuItem();
        editDialog = new javax.swing.JDialog();
        jLabel3 = new javax.swing.JLabel();
        lineCountTextSpin = new javax.swing.JSpinner();
        jLabel4 = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        jLabel6 = new javax.swing.JLabel();
        jLabel7 = new javax.swing.JLabel();
        pathDialogTextField = new javax.swing.JTextField();
        applyDialogButton = new javax.swing.JButton();
        cancelDialogButton = new javax.swing.JButton();
        lengthTextField = new javax.swing.JTextField();
        modeGroup = new javax.swing.ButtonGroup();
        jLabel1 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        mergeTable = new javax.swing.JTable();
        addButton = new javax.swing.JButton();
        removeButton = new javax.swing.JButton();
        upButton = new javax.swing.JButton();
        downButton = new javax.swing.JButton();
        jLabel2 = new javax.swing.JLabel();
        pathTextField = new javax.swing.JTextField();
        mergeButton = new javax.swing.JButton();
        browseButton = new javax.swing.JButton();
        jPanel1 = new javax.swing.JPanel();
        modeJSRERadio = new javax.swing.JRadioButton();
        modeNormalRadio = new javax.swing.JRadioButton();
        jLabel8 = new javax.swing.JLabel();
        totalFileLabel = new javax.swing.JLabel();
        totalLineLabel = new javax.swing.JLabel();

        popupMenu.setName("popupMenu"); // NOI18N

        editItem.setText("Edit line count in text");
        editItem.setName("editItem"); // NOI18N
        editItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editItemActionPerformed(evt);
            }
        });
        popupMenu.add(editItem);

        editDialog.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        editDialog.setTitle("Properties");
        editDialog.setName("editDialog"); // NOI18N
        editDialog.getContentPane().setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());

        jLabel3.setText("Line count in text document:");
        jLabel3.setName("jLabel3"); // NOI18N
        editDialog.getContentPane().add(jLabel3, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 140, -1, -1));

        lineCountTextSpin.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(1), Integer.valueOf(1), null, Integer.valueOf(1)));
        lineCountTextSpin.setName("lineCountTextSpin"); // NOI18N
        editDialog.getContentPane().add(lineCountTextSpin, new org.netbeans.lib.awtextra.AbsoluteConstraints(210, 140, 70, -1));

        jLabel4.setText("Line count in JSRE document:");
        jLabel4.setName("jLabel4"); // NOI18N
        editDialog.getContentPane().add(jLabel4, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 210, -1, -1));

        jLabel5.setText("ID Properties");
        jLabel5.setName("jLabel5"); // NOI18N
        editDialog.getContentPane().add(jLabel5, new org.netbeans.lib.awtextra.AbsoluteConstraints(150, 40, -1, -1));

        jLabel6.setText("(equals to length)");
        jLabel6.setName("jLabel6"); // NOI18N
        editDialog.getContentPane().add(jLabel6, new org.netbeans.lib.awtextra.AbsoluteConstraints(60, 240, -1, -1));

        jLabel7.setText("File path:");
        jLabel7.setName("jLabel7"); // NOI18N
        editDialog.getContentPane().add(jLabel7, new org.netbeans.lib.awtextra.AbsoluteConstraints(20, 80, -1, -1));

        pathDialogTextField.setEditable(false);
        pathDialogTextField.setName("pathDialogTextField"); // NOI18N
        editDialog.getContentPane().add(pathDialogTextField, new org.netbeans.lib.awtextra.AbsoluteConstraints(90, 80, 270, -1));

        applyDialogButton.setText("Apply");
        applyDialogButton.setName("applyDialogButton"); // NOI18N
        applyDialogButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                applyDialogButtonActionPerformed(evt);
            }
        });
        editDialog.getContentPane().add(applyDialogButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(100, 290, 80, -1));

        cancelDialogButton.setText("Cancel");
        cancelDialogButton.setName("cancelDialogButton"); // NOI18N
        cancelDialogButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelDialogButtonActionPerformed(evt);
            }
        });
        editDialog.getContentPane().add(cancelDialogButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(230, 290, -1, -1));

        lengthTextField.setEditable(false);
        lengthTextField.setName("lengthTextField"); // NOI18N
        editDialog.getContentPane().add(lengthTextField, new org.netbeans.lib.awtextra.AbsoluteConstraints(210, 210, 70, -1));

        setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());

        jLabel1.setText("List file to merge");
        jLabel1.setName("jLabel1"); // NOI18N
        add(jLabel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(430, 50, -1, -1));

        jScrollPane1.setName("jScrollPane1"); // NOI18N

        mergeTable.setModel(mergeModel);
        mergeTable.setName("mergeTable"); // NOI18N
        mergeTable.setSelectionMode(javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        MouseListener popupListener = new PopupListener();
        mergeTable.addMouseListener(popupListener);
        jScrollPane1.setViewportView(mergeTable);

        add(jScrollPane1, new org.netbeans.lib.awtextra.AbsoluteConstraints(200, 90, 580, 270));

        addButton.setText("Add");
        addButton.setToolTipText("Add file to merge[Ctrl + O]");
        addButton.setName("addButton"); // NOI18N
        addButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addButtonActionPerformed(evt);
            }
        });
        add(addButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(800, 110, 90, -1));

        removeButton.setText("Remove");
        removeButton.setName("removeButton"); // NOI18N
        removeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeButtonActionPerformed(evt);
            }
        });
        add(removeButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(800, 170, 90, -1));

        upButton.setText("Up");
        upButton.setName("upButton"); // NOI18N
        upButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                upButtonActionPerformed(evt);
            }
        });
        add(upButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(800, 240, 90, -1));

        downButton.setText("Down");
        downButton.setName("downButton"); // NOI18N
        downButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                downButtonActionPerformed(evt);
            }
        });
        add(downButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(800, 310, 90, -1));

        jLabel2.setText("Path to save:");
        jLabel2.setName("jLabel2"); // NOI18N
        add(jLabel2, new org.netbeans.lib.awtextra.AbsoluteConstraints(210, 430, -1, -1));

        pathTextField.setName("pathTextField"); // NOI18N
        add(pathTextField, new org.netbeans.lib.awtextra.AbsoluteConstraints(310, 430, 420, -1));

        mergeButton.setText("Merge");
        mergeButton.setName("mergeButton"); // NOI18N
        mergeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                mergeButtonActionPerformed(evt);
            }
        });
        add(mergeButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(490, 490, 90, -1));

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance().getContext().getActionMap(MergePanel.class, this);
        browseButton.setAction(actionMap.get("browseAction")); // NOI18N
        browseButton.setName("browseButton"); // NOI18N
        add(browseButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(800, 430, 90, 30));

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Mode", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.TOP));
        jPanel1.setName("jPanel1"); // NOI18N

        modeGroup.add(modeJSRERadio);
        modeJSRERadio.setSelected(true);
        modeJSRERadio.setText("JSRE Document");
        modeJSRERadio.setName("modeJSRERadio"); // NOI18N
        modeJSRERadio.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                modeJSRERadioItemStateChanged(evt);
            }
        });
        jPanel1.add(modeJSRERadio);

        modeGroup.add(modeNormalRadio);
        modeNormalRadio.setText("Normal Document");
        modeNormalRadio.setName("modeNormalRadio"); // NOI18N
        modeNormalRadio.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                modeNormalRadioItemStateChanged(evt);
            }
        });
        jPanel1.add(modeNormalRadio);

        add(jPanel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(10, 160, 180, 90));

        jLabel8.setText("Total:");
        jLabel8.setName("jLabel8"); // NOI18N
        add(jLabel8, new org.netbeans.lib.awtextra.AbsoluteConstraints(210, 380, -1, -1));

        totalFileLabel.setText("0 file(s)");
        totalFileLabel.setName("totalFileLabel"); // NOI18N
        add(totalFileLabel, new org.netbeans.lib.awtextra.AbsoluteConstraints(340, 380, -1, -1));

        totalLineLabel.setText("0 line(s)");
        totalLineLabel.setName("totalLineLabel"); // NOI18N
        add(totalLineLabel, new org.netbeans.lib.awtextra.AbsoluteConstraints(600, 380, -1, -1));
    }// </editor-fold>//GEN-END:initComponents

    private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed
        // TODO add your handling code here:
        String path = mapConfig.get(Config.DIRECTORY_PATH);
        JFileChooser fc = new JFileChooser(path);

        fc.setFileFilter(new TextFilter());
        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fc.setMultiSelectionEnabled(true);
        int val = fc.showOpenDialog(null);
        if (val == JFileChooser.APPROVE_OPTION) {
            File[] files = fc.getSelectedFiles();
            if (mode == JSRE_MODE) {
                // Hoat dong o che do JSRE
                ArrayList<File> errorFiles = new ArrayList<File>();
                for (File file : files) {
                    try {
                        JSREDocument doc = new JSREDocument(file);
                        Object[] dataRow = {doc, doc.getLastID()};
                        totalFileCount++;
                        totalLineCount += doc.getLastID().getCount();
                        totalFileLabel.setText(totalFileCount + " file(s)");
                        totalLineLabel.setText(totalLineCount + " line(s)");
                        mergeModel.addRow(dataRow);
                    } catch (FileNotFoundException ex) {
                        Logger.getLogger(MergePanel.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (UnsupportedEncodingException ex) {
                        Logger.getLogger(MergePanel.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (IOException ex) {
                        Logger.getLogger(MergePanel.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (IllegalArgumentException e) {
                        /* File input is not JSRE format */
                        errorFiles.add(file);
                    }
                }// end foreach
                if (!errorFiles.isEmpty()) {
                    StringBuilder mess = new StringBuilder();
                    mess.append("There are ");
                    mess.append(errorFiles.size());
                    mess.append(" file(s) are not legal for JSRE format:\n");
                    for (File err : errorFiles) {
                        mess.append(err.getAbsolutePath());
                        mess.append("\n");
                    }
                    JOptionPane.showMessageDialog(null, mess, "Warning", JOptionPane.WARNING_MESSAGE);
                }// end if errorFile
            } else {
                // Hoat dong o che do normal
                for (File file : files) {
                    Document doc = new Document(file);
                    Object[] data = new Object[] {doc, doc.size()};
                    totalFileCount++;
                    totalLineCount += doc.size();
                    totalFileLabel.setText(totalFileCount + " file(s)");
                    totalLineLabel.setText(totalLineCount + " line(s)");
                    mergeModel.addRow(data);
                }// end foreach file
            }// end if mode
        }// end if val
    }//GEN-LAST:event_addButtonActionPerformed

    private void removeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeButtonActionPerformed
        // TODO add your handling code here:
        int[] rows = mergeTable.getSelectedRows();
        if (rows.length == 0) {
            String message = "No selected row to delete";
            JOptionPane.showMessageDialog(null, message, "Warning", JOptionPane.WARNING_MESSAGE);
        } else {
            for (int i = rows.length - 1; i >= 0; i--) {
                if (mode == NORMAL_MODE) {
                    totalFileCount--;
                    totalLineCount -= (Integer) mergeModel.getValueAt(rows[i], 1);
                    totalFileLabel.setText(totalFileCount + " file(s)");
                    totalLineLabel.setText(totalLineCount + " line(s)");
                } else {
                    // mode JSRE
                    totalFileCount--;
                    totalLineCount -= ((ID) mergeModel.getValueAt(rows[i], 1)).getCount();
                    totalFileLabel.setText(totalFileCount + " file(s)");
                    totalLineLabel.setText(totalLineCount + " line(s)");
                }
                mergeModel.removeRow(rows[i]);
            }
        }
    }//GEN-LAST:event_removeButtonActionPerformed

    private void upButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_upButtonActionPerformed
        // TODO add your handling code here:
        int[] rows = mergeTable.getSelectedRows();
        if (rows.length == 0) {
            String message = "No selected row to delete";
            JOptionPane.showMessageDialog(null, message, "Warning", JOptionPane.WARNING_MESSAGE);
        } else if (rows[0] != 0) {
            int oldStart = rows[0];
            int oldEnd = rows[rows.length - 1];
            int newStart = rows[0] - 1;
            int newEnd = rows[rows.length - 1] - 1;
            mergeModel.moveRow(oldStart, oldEnd, newStart);
            mergeTable.setRowSelectionInterval(newStart, newEnd);
        }
    }//GEN-LAST:event_upButtonActionPerformed

    private void downButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_downButtonActionPerformed
        // TODO add your handling code here:
        int[] rows = mergeTable.getSelectedRows();
        if (rows.length == 0) {
            String message = "No selected row to delete";
            JOptionPane.showMessageDialog(null, message, "Warning", JOptionPane.WARNING_MESSAGE);
        } else if (rows[rows.length - 1] != mergeTable.getRowCount() - 1) {
            int oldStart = rows[0];
            int oldEnd = rows[rows.length - 1];
            int newStart = rows[0] + 1;
            int newEnd = rows[rows.length - 1] + 1;
            mergeModel.moveRow(oldStart, oldEnd, newStart);
            mergeTable.setRowSelectionInterval(newStart, newEnd);
        }
    }

    @Action
    public void browseAction() {
        String path = mapConfig.get(Config.DIRECTORY_PATH);
        JFileChooser fc = new JFileChooser(path);

        fc.setFileFilter(new TextFilter());
        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        int val = fc.showSaveDialog(null);
        if (val == JFileChooser.APPROVE_OPTION) {
            File file = fc.getSelectedFile();
            String filePath = file.getAbsolutePath();
            if (filePath.contains(".")) {
                pathTextField.setText(filePath);
            } else {
                pathTextField.setText(filePath + ".txt");
            }
        }
    }//GEN-LAST:event_downButtonActionPerformed

    private void mergeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_mergeButtonActionPerformed
        // TODO add your handling code here:
        String fileSavePath = pathTextField.getText();

        if (mode == JSRE_MODE) {
            // Hoat dong mode JSRE
            PrintWriter out = null;
            try {
                out = ReadWriteFile.writeFile(fileSavePath, "UTF-8");
            } catch (FileNotFoundException ex) {
                Logger.getLogger(MergePanel.class.getName()).log(Level.SEVERE, null, ex);
                JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
                return;
            } catch (UnsupportedEncodingException e) {
                JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
                e.printStackTrace();
                return;
            }// end try
            
            /* Merge all document in table */
            Vector<Vector> rows = mergeModel.getDataVector();
            List<JSREDocument> docList = new ArrayList<JSREDocument>();
            for (Vector row : rows) {
                JSREDocument doc = (JSREDocument) row.get(0);
                docList.add(doc);
            }
            JSREDocument result = docList.get(0);
            for (int i = 1; i < docList.size(); i++) {
    //            result.concat(docList.get(i));
                result = JSREDocument.merge(result, docList.get(i));
            }

            /* write to PrintWriter */
            for (JSRELine line : result.getLineList()) {
                out.print(line.getWholeLine());
                out.print("\r\n");
            }
            out.close();
        } else {
            // Hoat dong mode normal
            Vector<Vector> rows = mergeModel.getDataVector();
            Document retDoc = new Document();
            for (Vector row : rows) {
                Document tmpDoc = (Document) row.get(0);
                retDoc.append(tmpDoc);
            }// end foreach vector
            try {
                retDoc.print2File(fileSavePath);
            } catch (FileNotFoundException ex) {
                JOptionPane.showMessageDialog(null, "Can't save to this file. Check your permission or type correct path of parent dir",
                        "Error", JOptionPane.ERROR_MESSAGE);
            }
        }// end if mode
        
        JOptionPane.showMessageDialog(null, "Merge done", "Message", JOptionPane.INFORMATION_MESSAGE);
    }//GEN-LAST:event_mergeButtonActionPerformed

    private void editItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editItemActionPerformed
        // TODO add your handling code here:
        this.rowEdit = mergeTable.getSelectedRow();
        JSREDocument doc = (JSREDocument) mergeModel.getValueAt(this.rowEdit, 0);
        ID id = (ID) mergeModel.getValueAt(this.rowEdit, 1);
        pathDialogTextField.setText(doc.toString());
        lineCountTextSpin.setValue(id.getLineNumber());
        lengthTextField.setText(Integer.toString(id.getCount()));
        editDialog.setSize(400, 360);
        editDialog.setVisible(true);
    }//GEN-LAST:event_editItemActionPerformed

    private void applyDialogButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_applyDialogButtonActionPerformed
        // TODO add your handling code here:
        int newLineCountText = (Integer) lineCountTextSpin.getValue();
        ID newId = new ID(newLineCountText, Integer.parseInt(lengthTextField.getText()));
        if (!((ID) mergeModel.getValueAt(rowEdit, 1)).compareTo(newId)) {
            mergeModel.setValueAt(newId, rowEdit, 1);
        }
        editDialog.dispose();
    }//GEN-LAST:event_applyDialogButtonActionPerformed

    private void cancelDialogButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelDialogButtonActionPerformed
        // TODO add your handling code here:
        editDialog.dispose();
    }//GEN-LAST:event_cancelDialogButtonActionPerformed

    private void modeJSRERadioItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_modeJSRERadioItemStateChanged
        // TODO add your handling code here:
        if (modeJSRERadio.isSelected()) {
            mode = JSRE_MODE;
            JTableHeader th = mergeTable.getTableHeader();
            th.getColumnModel().getColumn(1).setHeaderValue("Line number in Text - Length");
            th.repaint();
        }
    }//GEN-LAST:event_modeJSRERadioItemStateChanged

    private void modeNormalRadioItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_modeNormalRadioItemStateChanged
        // TODO add your handling code here:
        if (modeNormalRadio.isSelected()) {
            mode = NORMAL_MODE;
            JTableHeader th = mergeTable.getTableHeader();
            th.getColumnModel().getColumn(1).setHeaderValue("Length");
            th.repaint();
        }
    }//GEN-LAST:event_modeNormalRadioItemStateChanged

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addButton;
    private javax.swing.JButton applyDialogButton;
    private javax.swing.JButton browseButton;
    private javax.swing.JButton cancelDialogButton;
    private javax.swing.JButton downButton;
    private javax.swing.JDialog editDialog;
    private javax.swing.JMenuItem editItem;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextField lengthTextField;
    private javax.swing.JSpinner lineCountTextSpin;
    private javax.swing.JButton mergeButton;
    private javax.swing.JTable mergeTable;
    private javax.swing.ButtonGroup modeGroup;
    private javax.swing.JRadioButton modeJSRERadio;
    private javax.swing.JRadioButton modeNormalRadio;
    private javax.swing.JTextField pathDialogTextField;
    private javax.swing.JTextField pathTextField;
    private javax.swing.JPopupMenu popupMenu;
    private javax.swing.JButton removeButton;
    private javax.swing.JLabel totalFileLabel;
    private javax.swing.JLabel totalLineLabel;
    private javax.swing.JButton upButton;
    // End of variables declaration//GEN-END:variables
    private DefaultTableModel mergeModel;
    private int rowEdit;
    private HashMap<String, String> mapConfig;
    private int mode;
    
    private int totalFileCount;
    private int totalLineCount;

    /**
     * Class for Listener, isPopupTrigger equal right click, it needs in both mousePressed and
     * mouseReleased method
     */
    class PopupListener extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            if (e.isPopupTrigger()) {
                showPopup(e);
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (e.isPopupTrigger()) {
                showPopup(e);
            }
        }

        private void showPopup(MouseEvent e) {
            popupMenu.show(e.getComponent(), e.getX(), e.getY());
            Point point = e.getPoint();
            /* Select row at location where right click */
            int row = mergeTable.rowAtPoint(point);
            mergeTable.setRowSelectionInterval(row, row);
        }
    }
}